package laya.util;

public abstract class SerialNoFactory
{
	protected long			m_nKey;
	protected long			m_nFinalCode;
	protected ProductCode	m_oCode;
	protected String		m_strSample;
	protected char[]		m_vOpt = null;
	protected String		m_strCharSet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	
	public abstract long hashCodeOpt();
    
	protected SerialNoFactory(ProductCode oCode, long nKey, String strSample)
	{
		m_oCode = oCode;
		m_nFinalCode = oCode.getCode();
		m_nKey = (nKey << 1) | 0x0001;	// singular is better
		m_strSample = strSample.toUpperCase();
		
		String strOpt = "";
		for (int i = 0; i < m_strSample.length(); i++)
		{
			char ch = m_strSample.charAt(i);
			if (m_strCharSet.indexOf(ch) >= 0)
			{
				strOpt += ch;
			}
		}
		
		m_vOpt = strOpt.toCharArray();
	}
	
    public long getNextSerialNo(StringBuffer sn)
    {
    	long hc;
    	
		if (true == optStrInc())
		{
			return -1;
		}
		
    	for (long i = 0; true; i++)
    	{
    		if ((m_oCode.COMPARE_MASK & (hc = hashCodeOpt())) == (m_oCode.COMPARE_MASK & m_nFinalCode))
    		{
    			m_oCode.setCode(hc);
    			if (m_oCode.isValid())
    			{
    				break;
    			}
    		}
    		
    		if ((i & 0x00000000007fffffl) == 0)
    		{
    			StringBuffer buff = new StringBuffer();
    			getFilledSn(buff);
	   			System.err.println("Sampling(" + i + "): " + buff + "; Code: " + m_oCode.toHexString(hc));
	   		}
    		
    		if (true == optStrInc())
    		{
    			return -1;
    		}
    	}

		getFilledSn(sn);
		return hc;
    }
    
    private boolean optStrInc()
    {
    	for (int i = 0; i < m_vOpt.length; i++)
    	{
    		int value = m_strCharSet.indexOf(m_vOpt[i]) + 1;
    		if (m_strCharSet.length() > value)
    		{
    			//increase 1
    			m_vOpt[i] = m_strCharSet.charAt(value);
    			return false;
    		}
    		else
    		{
    			//carry
    			m_vOpt[i] = m_strCharSet.charAt(0);
    		}
    	}
    	
    	return true;
    }
    
    private void getFilledSn(StringBuffer result)
    {
    	int index = 0;
    	for (int i = 0; i < m_strSample.length(); i++)
    	{
    		char ch = m_strSample.charAt(i);
    		if (m_strCharSet.indexOf(ch) >= 0)
    		{
    			result.append(m_vOpt[index++]);
    		}
    		else
    		{
    			result.append(ch);
    		}
    	}
    }
}